package communicationModule;

import generalObjects.GroupView;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Provides access to workerthreads for
 * {@link communicationModule.CMLayerAccess} which are responsible for sending
 * out messages to group members. This class also handles the different
 * multicast modes supported, reliable and basic multicast.
 * 
 */
public class Multicast {

    private final boolean reliable;
    private final String ident;
    private List<SendResult> deliverbuf;
    private final ReentrantLock delLock;
    private final ExecutorService threadpool;
    private final GroupView gView;

    public Multicast(final String ident, final boolean reliable,
            final ReentrantLock deliverlock, final GroupView gView) {
        this.ident = ident;
        this.reliable = reliable;
        delLock = deliverlock;
        threadpool = Executors.newCachedThreadPool();
        this.gView = gView;
    }

    public void setDeliverbuffer(final List<SendResult> deliverbuf) {
        this.deliverbuf = deliverbuf;
    }

    public List<SendResult> getDeliverbuffer() {
        return deliverbuf;
    }

    public void send(final List<MessageObject> msgList) {

        for (final MessageObject msg : msgList) {

            if (msg.getSender().equals(gView.getLeader())
                    && msg.getHeader().equals("update")) {
                for (final String key : gView.getView().keySet()) {
                    if (!msg.getGroupView().getView().containsKey(key)) {
                        msg.getGroupView().appendMember(key,
                                gView.getView().get(key),
                                gView.getVectorClock().get(key));
                    }
                }
            }

            if (reliable) {
                // R-Multicast always send.
                final BasicMulticast bM = new BasicMulticast(this, delLock, msg);
                threadpool.execute(bM);
            } else {
                // B-Multicast only send if self.
                if (msg.getSender().equals(ident)) {
                    final BasicMulticast bM = new BasicMulticast(this, delLock,
                            msg);
                    threadpool.execute(bM);
                } else {
                    delLock.lock();
                    deliverbuf
                            .add(new SendResult(msg, new ArrayList<String>()));
                    delLock.unlock();
                }
            }
        }
    }
}
